package cn.cjj.gulimall.ware.service.impl;

import cn.cjj.common.to.OrderEntityTo;
import cn.cjj.common.to.SkuHasStockTo;
import cn.cjj.common.to.mq.StockLockTo;
import cn.cjj.common.utils.R;
import cn.cjj.gulimall.ware.entity.WareOrderTaskDetailEntity;
import cn.cjj.gulimall.ware.entity.WareOrderTaskEntity;
import cn.cjj.gulimall.ware.exception.NoStockException;
import cn.cjj.gulimall.ware.feign.OrderFeignService;
import cn.cjj.gulimall.ware.feign.ProductFeignService;
import cn.cjj.gulimall.ware.service.WareOrderTaskDetailService;
import cn.cjj.gulimall.ware.service.WareOrderTaskService;
import cn.cjj.gulimall.ware.vo.OrderItemVo;
import cn.cjj.gulimall.ware.vo.WareSkuLockVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import cn.cjj.common.utils.PageUtils;
import cn.cjj.common.utils.Query;

import cn.cjj.gulimall.ware.dao.WareSkuDao;
import cn.cjj.gulimall.ware.entity.WareSkuEntity;
import cn.cjj.gulimall.ware.service.WareSkuService;
import org.springframework.transaction.annotation.Transactional;

@Slf4j
@Service("wareSkuService")
public class WareSkuServiceImpl extends ServiceImpl<WareSkuDao, WareSkuEntity> implements WareSkuService {

    @Autowired
    ProductFeignService productFeignService;

    @Autowired
    WareOrderTaskDetailService wareOrderTaskDetailService;

    @Autowired
    WareOrderTaskService wareOrderTaskService;

    @Autowired
    RabbitTemplate rabbitTemplate;

    @Autowired
    OrderFeignService orderFeignService;

    @Autowired
    WareSkuService wareSkuService;


    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<WareSkuEntity> page = this.page(
                new Query<WareSkuEntity>().getPage(params),
                new QueryWrapper<WareSkuEntity>()
        );

        return new PageUtils(page);
    }

    @Override
    public PageUtils queryPageByCondition(Map<String, Object> params) {
        QueryWrapper<WareSkuEntity> wrapper = new QueryWrapper<>();

        String skuId = (String) params.get("skuId");
        if (StringUtils.isNotEmpty(skuId) && !"0".equals(skuId)) {
            wrapper.eq("sku_id", skuId);
        }
        String wareId = (String) params.get("wareId");
        if (StringUtils.isNotEmpty(wareId) && !"0".equals(wareId)) {
            wrapper.eq("ware_id", wareId);
        }

        IPage<WareSkuEntity> page = this.page(
                new Query<WareSkuEntity>().getPage(params),
                wrapper
        );

        return new PageUtils(page);
    }

    @Transactional
    @Override
    public void addStock(Long skuId, Long wareId, Integer skuNum) {
        QueryWrapper<WareSkuEntity> wrapper = new QueryWrapper<>();
        wrapper.eq("sku_id", skuId).eq("ware_id", wareId);
        WareSkuEntity wareSkuEntity = baseMapper.selectOne(wrapper);
        if (wareSkuEntity != null) {
            baseMapper.addStock(skuId, wareId, skuId);
        } else {
            WareSkuEntity entity = new WareSkuEntity();
            entity.setSkuId(skuId);
            entity.setWareId(wareId);
            entity.setStock(skuNum);
            try {
                R info = productFeignService.info(skuId);
                if (info.getCode() == 0) {
                    Map<String, Object> map = (Map<String, Object>) info.get("skuInfo");
                    String skuName = (String) map.get("skuName");
                    entity.setSkuName(skuName);
                }
            } catch (Exception e) {
                log.error(e.getMessage());
            }
            baseMapper.insert(entity);
        }
    }

    @Override
    public List<SkuHasStockTo> getSkusHasStock(List<Long> skuIds) {
        List<SkuHasStockTo> SkuHasStockTos = skuIds.stream().map(skuId -> {
            SkuHasStockTo skuHasStockTo = new SkuHasStockTo();
            Long count = baseMapper.getSkuStock(skuId);

            skuHasStockTo.setSkuId(skuId);
            skuHasStockTo.setHasStock(count != null && count > 0);

            return skuHasStockTo;
        }).collect(Collectors.toList());

        return SkuHasStockTos;
    }

    @Transactional
    @Override
    public Boolean lockStock(WareSkuLockVo wareSkuLockVo) {
        WareOrderTaskEntity wareOrderTask = new WareOrderTaskEntity();
        wareOrderTask.setOrderSn(wareSkuLockVo.getOrderSn());
        wareOrderTaskService.save(wareOrderTask);

        List<Long> detailId = new ArrayList<>();

        List<OrderItemVo> locks = wareSkuLockVo.getLocks();
        locks.forEach(item -> {
            Long skuId = item.getSkuId();

            List<Long> wareIds = baseMapper.listWareIdsHasSkuStock(skuId);
            if (wareIds == null || wareIds.size() == 0) {
                throw new NoStockException(skuId);
            }

            boolean locked = false;
            for (Long wareId : wareIds) {
                long count = this.baseMapper.lockSkuStock(wareId, skuId, item.getCount());
                if (count == 1) {
                    locked = true;
                    WareOrderTaskDetailEntity wareOrderTaskDetail = new WareOrderTaskDetailEntity();
                    wareOrderTaskDetail.setSkuId(skuId);
                    wareOrderTaskDetail.setSkuName(item.getTitle());
                    wareOrderTaskDetail.setWareId(wareId);
                    wareOrderTaskDetail.setSkuNum(item.getCount());
                    wareOrderTaskDetail.setLockStatus(1);
                    wareOrderTaskDetail.setTaskId(wareOrderTask.getId());
                    wareOrderTaskDetailService.save(wareOrderTaskDetail);
                    detailId.add(wareOrderTaskDetail.getId());
                    break;
                }
            }
            if (!locked) {
                throw new NoStockException(skuId);
            }
        });

        StockLockTo stockLockTo = new StockLockTo();
        stockLockTo.setId(wareOrderTask.getId());
        stockLockTo.setDetailId(detailId);
        rabbitTemplate.convertAndSend("stock-event-exchange","stock.locked", stockLockTo);

        return true;
    }

    @Override
    public void unLockStock(Long skuId, Long wareId, Integer skuNum, Long id) {
        baseMapper.unLockStock(skuId, wareId, skuNum);

        WareOrderTaskDetailEntity wareOrderTaskDetail = new WareOrderTaskDetailEntity();
        wareOrderTaskDetail.setId(id);
        wareOrderTaskDetail.setLockStatus(2);
        wareOrderTaskDetailService.updateById(wareOrderTaskDetail);
    }

    @Override
    public void unLock(StockLockTo stockLockTo) {
        Long id = stockLockTo.getId();
        List<Long> detailId = stockLockTo.getDetailId();

        WareOrderTaskEntity wareOrderTask = wareOrderTaskService.getById(id);
        String orderSn = wareOrderTask.getOrderSn();

        int status = orderFeignService.getOrderStatus(orderSn);

        if (status == -1 || status == 4) {
            detailId.forEach(id2 -> {
                WareOrderTaskDetailEntity wareOrderTaskDetail = wareOrderTaskDetailService.getById(id2);
                if (wareOrderTaskDetail.getLockStatus() == 1) {
                    wareSkuService.unLockStock(wareOrderTaskDetail.getSkuId(), wareOrderTaskDetail.getWareId(),
                            wareOrderTaskDetail.getSkuNum(), id2);
                }
            });
        }

    }

    @Transactional
    @Override
    public void unLockStock(OrderEntityTo orderEntityTo) {
        String orderSn = orderEntityTo.getOrderSn();
        WareOrderTaskEntity wareOrderTask = wareOrderTaskService.getWareOrderTaskByOrderSn(orderSn);
        Long id = wareOrderTask.getId();
        List<WareOrderTaskDetailEntity> wareOrderTaskDetails = wareOrderTaskDetailService.getUnlockedOrderTaskDetail(id);

        if (wareOrderTaskDetails != null && wareOrderTaskDetails.size() > 0) {
            for (WareOrderTaskDetailEntity wareOrderTaskDetail : wareOrderTaskDetails) {
                unLockStock(wareOrderTaskDetail.getSkuId(), wareOrderTaskDetail.getWareId(),
                        wareOrderTaskDetail.getSkuNum(), wareOrderTaskDetail.getId());
            }
        }
    }
}